package com.indexingsystem.db.mongoDB;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.bson.Document;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;

import com.indexingsystem.boss.logback.LogCvt;
import com.indexingsystem.boss.utils.JsonUtils;
import com.indexingsystem.db.mongoDB.comon.MongoDBUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.Block;
import com.mongodb.DBCollection;
import com.mongodb.DBObject;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.UpdateOptions;

/**
 * 
 * @ClassName: MongoManager
 * 
 */
public class MongoManager extends MongoService {
	/**
	 * 
	 * buildFieldDBObject:构建需要查询的字段DBObject.
	 * 
	 * @param keysColl
	 *            需要查询的字段集合
	 * @return DBObject 需要查询的字段DBObject
	 * 
	 */
	public static DBObject buildFieldDBObject(Collection<String> keysColl) {
		BasicDBObject keys = new BasicDBObject();
		if (keysColl != null && keysColl.size() > 0) {
			for (String fieldName : keysColl) {
				keys.put( fieldName, 1 );
			}
		}
		return keys;
	}

	/**
	 * 
	 * reverseSort:反转排序条件 （原来是升序的字段反转为降序，反之亦然）.
	 * 
	 * @param srot
	 * 
	 */
	public static void reverseSort(DBObject srot) {
		Map<String, Integer> map = (Map<String, Integer>) srot.toMap();
		Set<String> keys = map.keySet();
		for (String key : keys) {
			map.put( key, 0 - map.get( key ) );
		}
		srot.putAll( map );
		// return srot;
	}

	/**
	 * 新增单个对象.
	 * 
	 * @param document
	 * @param connName
	 */
	@Override
	public void add(Document document, String connName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( connName );
			dbCollection.insertOne( document );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo add: collection=" ).append( connName ).append( ",SQL=[" ).append( JsonUtils.toJson( document ) )
					.append( "]" ).toString() );
			closeConnection();
		}
	}

	/**
	 * 
	 * add:批量添加
	 * 
	 * @param dbObjects
	 * @param connName
	 * @return
	 * 
	 */
	@Override
	public void addList(List<Document> list, String connName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( connName );
			dbCollection.insertMany( list );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo addList: collection=" ).append( connName ).append( ",SQL=[" ).append( JsonUtils.toJson( list ) )
					.append( "]" ).toString() );
			closeConnection();
		}
	}

	/**
	 * 插入一条数据
	 * 
	 * @param bean
	 */
	@Override
	public <T> void insertOne(Object object, String connName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( connName );
			dbCollection.insertOne( MongoDBUtils.transform2Doc( object ) );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo insertOne: collection=" ).append( connName ).append( ",SQL=[" )
					.append( JsonUtils.toJson( object ) ).append( "]" ).toString() );
			closeConnection();
		}
	}

	/**
	 * 
	 * add:批量添加
	 * 
	 * @param dbObjects
	 * @param connName
	 * @return
	 * 
	 */
	@Override
	public void addArray(Document[] dbObjects, String connName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( connName );
			dbCollection.insertMany( Arrays.asList( dbObjects ) );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo addArray: collection=" ).append( connName ).append( ",SQL=[" )
					.append( JsonUtils.toJson( dbObjects ) ).append( "]" ).toString() );
			closeConnection();
		}
	}

	// 打印查询的结果集
	public void printCollection(String mql, MongoCollection<Document> mc) {
		LogCvt.info( mql );
		FindIterable<Document> iterable = mc.find();
		iterable.forEach( new Block<Document>() {
			public void apply(final Document document) {
				System.out.println( document );
			}
		} );
		LogCvt.info( "------------------------------------------------------" );
	}

	/**
	 * 删除数据
	 */
	@Override
	public void delete(Map<String, Object> condition, String connName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( connName );
			BasicDBObject filter = new BasicDBObject();
			Set<String> keys = condition.keySet();
			for (String key : keys) {
				if (key.equals( "id" )) {
					filter.append( "_id", new ObjectId( condition.get( key ) + "" ) );
					continue;
				}
				filter.append( key, condition.get( key ) );
			}
			dbCollection.deleteMany( filter );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo delete: collection=" ).append( connName ).append( ",SQL=[" )
					.append( JsonUtils.toJson( condition ) ).append( "]" ).toString() );
			closeConnection();
		}
	}

	/**
	 * 删除所有数据.
	 */
	@Override
	public void deleteAll(String connName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( connName );
			dbCollection.deleteMany( new Document() );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo delete: collection=" ).append( connName ).toString() );
			closeConnection();
		}
	}

	/**
	 * 查询所有数据
	 */
	@Override
	public List<Document> findAll(Class clazz, String connName) {
		MongoCollection<Document> dbCollection = null;
		final List<Document> newLins = new ArrayList<>();
		try {
			dbCollection = getReadDBCollection( connName );
			Block<Document> saveBlock = new Block<Document>() {
				@Override
				public void apply(final Document document) {
					newLins.add( document );
				}
			};
			// 查询
			MongoCollection<Document> collection = dbCollection;
			collection.find().forEach( saveBlock );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo findAll: collection=" ).append( connName ).toString() );
			closeConnection();
		}
		return newLins;
	}

	/**
	 * 查找集合内所有Document
	 * 
	 * @param collName
	 * @return
	 */
	@Override
	public List<Document> findAll(String collName) {
		MongoCollection<Document> dbCollection = null;
		List<Document> result = new ArrayList<Document>();
		try {
			dbCollection = getReadDBCollection( collName );
			FindIterable<Document> findIterable = dbCollection.find();
			MongoCursor<Document> mongoCursor = findIterable.iterator();
			while (mongoCursor.hasNext()) {
				result.add( mongoCursor.next() );
			}
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo findAll: collection=" ).append( collName ).toString() );
			closeConnection();
		}
		return result;
	}

	/**
	 * 查询指定数据
	 */
	@Override
	public <T> List<T> findCondition(Map<String, Object> condition, Class clazz, String connName) {
		List<T> object = null;
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getReadDBCollection( connName );
			BasicDBObject filter = new BasicDBObject();
			Set<String> keys = condition.keySet();
			for (String key : keys) {
				if (key.equals( "id" )) {
					filter.append( "_id", new ObjectId( condition.get( key ) + "" ) );
					continue;
				}
				filter.append( key, condition.get( key ) );
			}
			FindIterable<Document> it = dbCollection.find( filter );
			MongoCursor<Document> cursor = it.iterator();
			object = MongoDBUtils.data2Bean( clazz, cursor );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo findAll: collection=" ).append( connName ).append( ",SQL=[" )
					.append( JsonUtils.toJson( condition ) ).append( "]" ).toString() );
			closeConnection();
		}

		return object;
	}

	/**
	 * 单页分页查询.
	 * 
	 * @param db
	 * @param tableName
	 * @param bson
	 * @param skip
	 * @param limit
	 * @return
	 */
	@Override
	public List<Document> queryPages(String connName, Bson bson, Document pxObj, Document fetchFields, int pageNo, int pageSize) {
		MongoCollection<Document> dbCollection = null;
		int skip = (pageNo - 1) * pageSize;
		int limit = pageSize;

		// int skip = pageNo;
		// int limit = pageSize;
		final List<Document> newLins = new ArrayList<>();
		try {
			dbCollection = getReadDBCollection( connName );

			Block<Document> saveBlock = new Block<Document>() {
				@Override
				public void apply(final Document document) {
					newLins.add( document );
				}
			};
			// 查询
			MongoCollection<Document> collection = dbCollection;
			if (null != pxObj) {
				if (null != fetchFields) {
					collection.find( bson ).projection( fetchFields ).sort( pxObj ).skip( skip ).limit( limit ).forEach( saveBlock );
				} else {
					collection.find( bson ).sort( pxObj ).skip( skip ).limit( limit ).forEach( saveBlock );
				}
			} else {
				if (null != fetchFields) {
					collection.find( bson ).projection( fetchFields ).skip( skip ).limit( limit ).forEach( saveBlock );
				} else {
					collection.find( bson ).skip( skip ).limit( limit ).forEach( saveBlock );
				}
			}
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo queryPages: collection=" ).append( connName ).append( ",SQL=[" ).append( JsonUtils.toJson( bson ) )
					.append( "]" ).toString() );
			closeConnection();
		}

		return newLins;
		// MongoDatabase mongoDatabase = Mongodb.getMongoDb().getDatabase(
		// "db_name" );
		// List<String> taskIds = new ArrayList<>();
		// taskIds.add( "123" );
		// taskIds.add( "456" );
		// // bson就相当于where条件
		// Bson bson = Filters.and( Filters.eq( "status", 0 ), Filters.eq(
		// "dep", 1 ), Filters.in( "taskId", taskIds ) );
		// // 查询tableName表中前1万条数据
		// List<Document> myList = MonitorUtil.query( mongoDatabase, tableName,
		// bson, 0, 10000 );
		//

	}

	/**
	 * 多页分页查询.
	 * 
	 * @param db
	 * @param tableName
	 * @param bson
	 * @param pageSize
	 * @return
	 */
	@Override
	public List<Document> queryPages(String connName, Bson bson, Document pxObj, Document fetchFields, int pageSize) {
		MongoCollection<Document> dbCollection = null;
		// 分页查询
		List<Document> list = new ArrayList<>();
		try {
			dbCollection = getReadDBCollection( connName );
			long count = dbCollection.count( bson );
			int loops = (int) ((count + pageSize - 1) / pageSize);
			for (int i = 0; i < loops; i++) {
				List<Document> newFinds = queryPages( connName, bson, pxObj, fetchFields, i * pageSize, pageSize );
				list.addAll( newFinds );
			}
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo queryPages: collection=" ).append( connName ).append( ",SQL=[" ).append( JsonUtils.toJson( bson ) )
					.append( "]" ).toString() );
			closeConnection();
		}
		return list;

		/**
		 * Bson bsonLinks = Filters.and( Filters.gt("lud", task_beginTime),
		 * Filters.eq("rd", task_domain), Filters.gte("dep", 2),
		 * Filters.lte("dep",7)); //分页查询 List<Document> links =
		 * MonitorUtil.queryPages(mongoDatabase, tableName, bsonLinks, 1000);
		 */
	}

	/**
	 * 带条件聚合查询.
	 * 
	 * @param aggregateList
	 * @param connName
	 * @return
	 */
	@Override
	public List<Document> queryAggregateList(Bson aggregateList, Class clazz, String connName) {
		MongoCollection<Document> dbCollection = null;
		final List<Document> newLins = new ArrayList<>();
		try {
			dbCollection = getReadDBCollection( connName );
			Block<Document> saveBlock = new Block<Document>() {
				@Override
				public void apply(final Document document) {
					newLins.add( document );
				}
			};
			MongoCollection<Document> collection = dbCollection;
			collection.find( aggregateList ).forEach( saveBlock );

			// FindIterable<Document> resultset = dbCollection.find(
			// aggregateList );
			// MongoCursor<Document> cursor = resultset.iterator();
			// object = MongoDBUtils.data2Bean( clazz, cursor );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo queryAggregateList: collection=" ).append( connName ).append( ",SQL=[" )
					.append( JsonUtils.toJson( aggregateList ) ).append( "]" ).toString() );
			closeConnection();
		}
		return newLins;

	}

	/**
	 * 获取文档查询条件的总数量.
	 * 
	 * @param aggregateList
	 * @param connName
	 * @return
	 */
	@Override
	public Integer queryAggregateListMaxCount(Bson aggregateList, String connName) {
		MongoCollection<Document> dbCollection = null;
		final List<Document> newLins = new ArrayList<>();
		try {
			dbCollection = getReadDBCollection( connName );
			Block<Document> saveBlock = new Block<Document>() {
				@Override
				public void apply(final Document document) {
					newLins.add( document );
				}
			};
			MongoCollection<Document> collection = dbCollection;
			collection.find( aggregateList ).forEach( saveBlock );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo queryAggregateListMaxCount: collection=" ).append( connName ).append( ",SQL=[" )
					.append( JsonUtils.toJson( aggregateList ) ).append( "]" ).toString() );
			closeConnection();
		}
		return newLins.size();
	}

	/**
	 * 删除单个集合:带条件查询符合结果的执行删除.
	 * 
	 * @param connName
	 * @param document
	 */
	@Override
	public void deleteOne(String connName, Document document) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( connName );
			dbCollection.deleteOne( document );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo deleteOne: collection=" ).append( connName ).toString() );
			closeConnection();
		}
	}

	/**
	 * 删除指定的一条数据
	 * 
	 * @param b
	 * @param collName
	 */
	@Override
	public void deleteOne(Bson bson, String collName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( collName );
			dbCollection.deleteOne( bson );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo deleteOne: collection=" ).append( collName ).toString() );
			closeConnection();
		}
	}

	/**
	 * 删除指定的所有数据
	 * 
	 * @param b
	 * @param collName
	 */
	public void deleteAll(Bson bson, String collName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( collName );
			dbCollection.deleteMany( bson );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo deleteAll: collection=" ).append( collName ).toString() );
			closeConnection();
		}
	}

	/**
	 * 单个修改集合：带查询条件修改，带UpdateOptions 条件.
	 * 
	 * @param filter
	 * @param updateDoc
	 * @param options
	 * @param connName
	 */
	@Override
	public void updateOne(Bson filter, Bson updateDoc, UpdateOptions options, String connName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( connName );
			dbCollection.updateOne( filter, updateDoc, options );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo updateOne: collection=" ).append( connName ).append( ",SQL=[" )
					.append( JsonUtils.toJson( updateDoc ) ).append( "]" ).toString() );
			closeConnection();
		}

		// 记录不存在新增，存在更新
		// Bson filter = Filters.eq("name", "裴xx");
		// Bson xxdoc = new Document("$set", new Document("name",
		// "裴xx").append("age",350).append("email","kkk@qq.com"));
		// UpdateOptions options = new UpdateOptions().upsert(true);
		// mc.updateOne(filter,xxdoc,options);
		//
		// Bson filter2 = Filters.eq("name", "裴xx");
		// Bson xxdoc2 = new Document("$set", new Document("name",
		// "裴xx更新后").append("age",350).append("email","kkk@qq.com"));
		// UpdateOptions options2 = new UpdateOptions().upsert(true);
	}

	/**
	 * 单过滤条件修改单个集合.
	 */
	@Override
	public void updateOne(Bson filter, Bson updateDoc, String connName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( connName );
			UpdateOptions options = new UpdateOptions().upsert( true );
			dbCollection.updateOne( filter, updateDoc, options );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo updateOne: collection=" ).append( connName ).append( ",SQL=[" )
					.append( JsonUtils.toJson( updateDoc ) ).append( "]" ).toString() );
			closeConnection();
		}
	}

	/**
	 * 按查询条件批量修改
	 * 
	 * 例子：//collection.updateMany(Filters.eq("likes", 100), new Document("$set",
	 * new Document("likes",200)) );
	 * 
	 * 
	 * 
	 * @param b
	 * @param doc
	 * @param collName
	 */
	@Override
	public void updateAll(Bson bson, Document doc, String collName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( collName );
			dbCollection.updateMany( bson, doc );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo updateOne: collection=" ).append( collName ).append( ",SQL=[" ).append( JsonUtils.toJson( doc ) )
					.append( "]" ).toString() );
			closeConnection();
		}
	}

	/**
	 * 替换更新整个document。
	 * 
	 * @param bson
	 * @param newDocument
	 * @param options
	 */
	@Override
	public void replaceOne(Bson bson, Document newDocument, UpdateOptions options, String collName) {
		MongoCollection<Document> dbCollection = null;
		try {
			dbCollection = getWriteDBCollection( collName );
			dbCollection.replaceOne( bson, newDocument );
		} catch (Exception e) {
			LogCvt.error( e.getMessage(), e );
		} finally {
			LogCvt.debug( new StringBuffer( "mongo updateOne: collection=" ).append( collName ).append( ",SQL=[" )
					.append( JsonUtils.toJson( newDocument ) ).append( "]" ).toString() );
			closeConnection();
		}
	}
}